"""数据查询工具

此模块提供数据查询工具，用于 LLM Agent 调用系统 API。

工作流程：
1. 前端用户登录 → 获取 token
2. 前端调用 AI 对话接口 → 在请求头中传递 token
3. AI 后端 (api.py) 接收请求 → 提取 token 并存储到上下文
4. 工具函数调用 → 从上下文自动获取 token
5. _call_api 使用 token → 调用系统 API 进行认证

环境配置（通过 config.py 和 ENV 环境变量控制）：
- 开发环境（ENV=development）：http://localhost:5080/
- 生产环境（ENV=production）：https://ecgs.fowep.com/prod-api
- 可通过环境变量 BACKEND_API_BASE_URL 覆盖默认配置

AI 对话服务器：http://localhost:9999/

注意：使用多种机制确保 token 能被正确传递：
- 优先使用 contextvars（在异步环境中传递 token）
- 备用：全局变量（当 contextvars 无法工作时）
"""
import requests
from langchain_core.tools import tool
from config.config import BACKEND_API_BASE_URL
import contextvars
from typing import Optional, Annotated, List, Dict, Any
from datetime import datetime
import json
import logging
from .sse_helper import send_sse_event

logger = logging.getLogger(__name__)

# 默认请求超时时间（秒）
DEFAULT_TIMEOUT = 30

# 获取上下文中的 token（由 api.py 设置）
# 当前端传递了 token，api.py 会将其设置到这个上下文变量中
# 工具函数可以通过 request_token.get() 获取 token
try:
    from api import request_token
except ImportError:
    # 如果无法导入（例如直接运行此模块），创建本地的上下文变量
    request_token = contextvars.ContextVar('request_token', default=None)

# 全局变量作为后备方案（确保在任何情况下都能获取 token）
_global_token = None

def set_global_token(token: Optional[str]):
    """设置全局 token（备用方案）"""
    global _global_token
    _global_token = token
    if token:
        logger.info(f"[data_query] 📝 全局 token 已设置")

def get_global_token() -> Optional[str]:
    """获取全局 token（备用方案）"""
    return _global_token


class RuleEngine:
    """规则引擎 - 用于过滤时间序列数据
    
    支持的操作符：
    • > : 大于
    • < : 小于
    • >= : 大于等于
    • <= : 小于等于
    • == : 等于
    • != : 不等于
    • in : 包含在列表中
    • contains : 字符串包含
    
    支持的逻辑运算：AND, OR
    """
    
    OPERATORS = {
        '>': lambda a, b: a > b,
        '<': lambda a, b: a < b,
        '>=': lambda a, b: a >= b,
        '<=': lambda a, b: a <= b,
        '==': lambda a, b: a == b,
        '!=': lambda a, b: a != b,
        'in': lambda a, b: a in b,
        'contains': lambda a, b: b in str(a),
    }
    
    def __init__(self, rules_config: Dict[str, Any]):
        """初始化规则引擎
        
        Args:
            rules_config: 规则配置字典，格式如下：
            {
                "rules": [
                    {
                        "model_id": "pressure_01",
                        "field": "value",
                        "operator": ">",
                        "value": 1.6,
                        "operator_to_next": "AND"  # 可选，默认为 AND
                    },
                    ...
                ]
            }
        """
        self.rules = rules_config.get("rules", [])
        self.model_id_data_map = {}  # 用于存储不同 model_id 的时间序列数据
        
    def set_data(self, model_id: str, timestamps: List[str], values: List[Any]):
        """为特定 model_id 设置时间序列数据
        
        Args:
            model_id: 物理模型编号
            timestamps: 时间戳列表
            values: 数值列表
        """
        if len(timestamps) != len(values):
            raise ValueError(f"时间戳和数值长度不匹配: {len(timestamps)} vs {len(values)}")
        
        self.model_id_data_map[model_id] = {
            "timestamps": timestamps,
            "values": values
        }
    
    def validate_rules(self) -> tuple[bool, Optional[str]]:
        """验证规则格式
        
        Returns:
            (是否有效, 错误信息)
        """
        if not self.rules or not isinstance(self.rules, list):
            return False, "规则必须是列表格式"
        
        for idx, rule in enumerate(self.rules):
            # 检查必填字段
            required_fields = ["model_id", "field", "operator", "value"]
            for field in required_fields:
                if field not in rule:
                    return False, f"规则 {idx} 缺少必填字段: {field}"
            
            # 检查操作符是否支持
            operator = rule.get("operator")
            if operator not in self.OPERATORS:
                return False, f"规则 {idx} 不支持的操作符: {operator}。支持的操作符: {list(self.OPERATORS.keys())}"
            
            # 检查逻辑运算符
            logic_op = rule.get("operator_to_next", "AND")
            if logic_op not in ["AND", "OR"]:
                return False, f"规则 {idx} 的逻辑运算符必须是 AND 或 OR，但得到: {logic_op}"
        
        return True, None
    
    def evaluate_single_rule(self, rule: Dict[str, Any], index: int) -> tuple[List[int], Optional[str]]:
        """计算单条规则
        
        Args:
            rule: 规则字典
            index: 规则索引
        
        Returns:
            (满足条件的数据点索引列表, 错误信息)
        """
        model_id = rule.get("model_id")
        field = rule.get("field")
        operator = rule.get("operator")
        compare_value = rule.get("value")
        
        # 获取该 model_id 的数据
        if model_id not in self.model_id_data_map:
            return [], f"规则 {index} 引用的 model_id '{model_id}' 没有数据"
        
        data = self.model_id_data_map[model_id]
        
        # 目前只支持 "value" 字段
        if field != "value":
            return [], f"规则 {index} 目前只支持 'value' 字段"
        
        values = data["values"]
        matching_indices = []
        
        try:
            operator_func = self.OPERATORS[operator]
            
            for idx, val in enumerate(values):
                # 处理类型转换
                try:
                    if operator in ['>', '<', '>=', '<=']:
                        # 数值比较
                        val_num = float(val)
                        compare_num = float(compare_value)
                        if operator_func(val_num, compare_num):
                            matching_indices.append(idx)
                    elif operator == 'in':
                        # 列表包含
                        if operator_func(val, compare_value):
                            matching_indices.append(idx)
                    elif operator == 'contains':
                        # 字符串包含
                        if operator_func(val, compare_value):
                            matching_indices.append(idx)
                    else:
                        # == 和 !=
                        if operator == '==' and val == compare_value:
                            matching_indices.append(idx)
                        elif operator == '!=' and val != compare_value:
                            matching_indices.append(idx)
                except (ValueError, TypeError) as e:
                    logger.warning(f"[rule_engine] ⚠️ 规则 {index} 类型转换失败: {str(e)}")
                    continue
        
        except Exception as e:
            return [], f"规则 {index} 执行失败: {str(e)}"
        
        return matching_indices, None
    
    def evaluate_rules(self) -> tuple[List[int], Optional[str]]:
        """计算所有规则的结果（支持 AND/OR 逻辑）
        
        Returns:
            (满足条件的数据点索引列表, 错误信息)
        """
        # 验证规则
        is_valid, error = self.validate_rules()
        if not is_valid:
            return [], error
        
        if not self.rules:
            return [], "没有规则"
        
        # 计算第一条规则的结果
        result_indices, error = self.evaluate_single_rule(self.rules[0], 0)
        if error:
            return [], error
        
        result_set = set(result_indices)
        
        # 逐条处理后续规则
        for idx, rule in enumerate(self.rules[1:], start=1):
            logic_op = self.rules[idx - 1].get("operator_to_next", "AND")
            current_indices, error = self.evaluate_single_rule(rule, idx)
            
            if error:
                return [], error
            
            current_set = set(current_indices)
            
            # 应用逻辑运算
            if logic_op == "AND":
                result_set = result_set.intersection(current_set)
            elif logic_op == "OR":
                result_set = result_set.union(current_set)
        
        # 返回有序的索引列表
        return sorted(list(result_set)), None
    
    def filter_data(self) -> Dict[str, Any]:
        """根据规则过滤所有 model_id 的数据
        
        Returns:
            过滤后的数据字典，格式与输入相同
        """
        matching_indices, error = self.evaluate_rules()
        
        if error:
            return {
                "error": error,
                "filtered_data": {}
            }
        
        # 过滤每个 model_id 的数据
        filtered_data = {}
        for model_id, data in self.model_id_data_map.items():
            filtered_timestamps = [data["timestamps"][i] for i in matching_indices]
            filtered_values = [data["values"][i] for i in matching_indices]
            
            filtered_data[model_id] = {
                "timestamps": filtered_timestamps,
                "values": filtered_values,
                "original_count": len(data["values"]),
                "filtered_count": len(filtered_values)
            }
        
        return {
            "error": None,
            "matching_indices": matching_indices,
            "filtered_data": filtered_data
        }


def _call_api(endpoint: str, method: str = "GET", params: dict = None, body: dict = None, token: str = None) -> dict:
    """内部API调用函数
    
    此函数用于调用系统后端 API，API 地址由 config.py 中的 BACKEND_API_BASE_URL 配置决定：
    - 开发环境：http://localhost:5080/
    - 生产环境：https://ecgs.fowep.com/prod-api
    
    工具调用时会自动从上下文获取用户 token，用于 API 认证。
    
    Args:
        endpoint: API端点路径（例如 "/iot/device/runningStatusMap"）
        method: HTTP方法（GET, POST, PUT, DELETE）
        params: URL查询参数（作为 query string 传递）
        body: 请求体（用于 POST/PUT 请求）
        token: 用户 token（用于认证），如果不提供则从上下文或全局变量获取
        
    Returns:
        API返回的 JSON 数据或错误信息
        
    示例：
        get_device_status = _call_api(
            endpoint="/iot/device/runningStatusMap",
            method="GET",
            params={"deviceId": "121794"}
        )
    """
    if not endpoint.startswith("/"):
        endpoint = "/" + endpoint
    
    url = f"{BACKEND_API_BASE_URL}{endpoint}"
    
    try:
        method = method.upper()
        headers = {
            "Content-Type": "application/json",
            "User-Agent": "Apifox/1.0.0 (https://apifox.com)",
            "Accept": "*/*",
            "Connection": "keep-alive"
        }
        
        # Token 获取优先级：参数 > 上下文变量 > 全局变量
        if not token:
            # 首先尝试从上下文获取
            token = request_token.get()
            if not token:
                # 如果上下文没有，尝试从全局变量获取（备用方案）
                token = get_global_token()
        
        # 调试日志
        logger.info(f"[data_query] 🔍 调用 API: {method} {url}")
        if token:
            logger.info(f"[data_query] ✅ Token 已找到，来源: {'上下文' if request_token.get() else '全局变量'}")
        else:
            logger.warning(f"[data_query] ⚠️ 警告: 未找到 token，请求可能被拒绝")
        
        if token:
            # 使用 Bearer token 格式
            headers["Authorization"] = f"Bearer {token}"
            logger.info(f"[data_query] 📤 请求头已添加 Authorization: Bearer {token[:20]}...")
        
        # 打印请求内容
        logger.info(f"[data_query] 📋 请求方法: {method}")
        logger.info(f"[data_query] 📋 请求URL: {url}")
        if params:
            logger.info(f"[data_query] 📋 请求参数: {json.dumps(params, ensure_ascii=False, indent=2)}")
        if body:
            logger.info(f"[data_query] 📋 请求体: {json.dumps(body, ensure_ascii=False, indent=2)}")
        logger.info(f"[data_query] 📋 请求头: {json.dumps(headers, ensure_ascii=False, indent=2)}")
        
        if method == "GET":
            response = requests.get(url, params=params or {}, headers=headers, timeout=DEFAULT_TIMEOUT)
        elif method == "POST":
            response = requests.post(url, json=body or {}, params=params or {}, headers=headers, timeout=DEFAULT_TIMEOUT)
        elif method == "PUT":
            response = requests.put(url, json=body or {}, params=params or {}, headers=headers, timeout=DEFAULT_TIMEOUT)
        elif method == "DELETE":
            response = requests.delete(url, params=params or {}, headers=headers, timeout=DEFAULT_TIMEOUT)
        else:
            return {"error": f"不支持的HTTP方法: {method}"}
        
        response.raise_for_status()
        response_data = response.json()
        logger.info(f"[data_query] ✅ API 响应状态码: {response.status_code}")
        logger.info(f"[data_query] ✅ API 响应内容: {json.dumps(response_data, ensure_ascii=False, indent=2)}")
        return response_data
        
    except requests.exceptions.Timeout:
        return {"error": f"请求超时，请稍后重试（超过 {DEFAULT_TIMEOUT} 秒）"}
    except requests.exceptions.ConnectionError:
        return {"error": f"无法连接到后端服务器: {BACKEND_API_BASE_URL}"}
    except requests.exceptions.HTTPError as e:
        return {"error": f"HTTP错误: {e.response.status_code} - {e.response.text}"}
    except Exception as e:
        return {"error": f"查询失败: {str(e)}"}


@tool
def query_villages(
    village_name: Annotated[Optional[str], "【可选】小区名字，支持模糊查询。例如：'阳光小区'、'阳光'、'花园'等。如果不提供则返回所有小区。"] = None
) -> dict:
    """查询小区信息（支持模糊查询或获取全部）
    
    功能说明：
    • 当不提供 village_name 参数时：获取系统中所有可用的小区列表（精简版）
    • 当提供 village_name 参数时：通过小区名字进行模糊查询
    • 如果返回结果超过200个小区，会提示用户提供关键词进行筛选
    
    不提供参数时返回的信息（精简版）：
    - villageName: 小区名字
    - villageNumber: 小区编号
    - villageId: 小区ID
    - onlineStatus: 在线情况（在线/离线/告警）
    
    提供查询参数时返回的信息（详细版）：
    - villageName: 小区名字
    - detailedAddress: 详细地址
    - villageNumber: 小区编号
    - villageId: 小区ID
    - onlineStatus: 在线情况（在线/离线/告警/仅建档/设备已删除）
    - status: 原始状态码
    
    使用场景：
    • 获取系统中所有可用的小区列表
    • 通过小区名字查找具体小区信息
    • 了解各个小区的在线状态
    • 为其他查询选择合适的小区编号
    """
    # 工具会自动从上下文中获取 token
    params = {}
    if village_name:
        params["villageName"] = village_name
    
    # 统一使用 /ai/query/villages 端点
    response = _call_api(
        endpoint="/ai/query/villages",
        method="GET",
        params=params if params else None
    )
    
    # 检查返回结果
    if response.get("error"):
        return response
    
    # 检查数据数量
    data = response.get("data", [])
    if isinstance(data, list) and len(data) > 200:
        return {
            "code": 400,
            "msg": f"返回结果过多（{len(data)}个），请提供关键词进行筛选，例如：'阳光'、'花园'、'学府'等",
            "data": [],
            "total_count": len(data)
        }
    
    return response


@tool
def query_village_device_running(
    village_number: Annotated[str, "小区编号，精确查询。例如：'VN001'、'A001'等。返回该小区所有关联设备的实时运行数据。"]
) -> dict:
    """查询小区设备运行情况
    
    查询指定小区关联设备的实时运行状态和物理模型数据，包括各监测位点的实时数值。
    
    返回结果为小区设备信息列表，每个小区包含：
    - villageName: 小区名字
    - villageId: 小区ID
    - devices[]: 设备列表，每个设备包含：
        - deviceId: 设备ID
        - deviceName: 设备名字
        - serialNumber: 设备序列号
        - thingsModels[]: 物理模型（监测位点）列表，每个包含：
            - modelId: 位点标识符
            - modelName: 位点名字（例：压力、温度）
            - value: 实时数值
            - unit: 单位（例：MPa、℃）
            - type: 位点类型（1=属性、2=功能）
    
    使用场景：
    • 查看小区设备当前工作状态
    • 了解各监测位点的实时数据
    • 诊断设备异常（如值超出正常范围）
    """
    # 工具会自动从上下文中获取 token
    return _call_api(
        endpoint="/ai/query/village/device/running",
        method="GET",
        params={"villageNumber": village_number}
    )


@tool
def query_village_device_history(
    village_number: Annotated[str, "小区编号，精确查询。例如：'VN001'、'A001'等。必填参数。"],
    start_time: Annotated[str, "开始时间，必须格式为 'yyyy-MM-dd HH:mm:ss'。例如：'2024-01-01 00:00:00'。必填参数。"],
    end_time: Annotated[str, "结束时间，必须格式为 'yyyy-MM-dd HH:mm:ss'。例如：'2024-01-31 23:59:59'。必须晚于开始时间。必填参数。"],
    model_id: Annotated[List[str], "物理模型编号列表，精确匹配。例如：['temp_01', 'pressure_01'] 或 ['flow_01']。可以一次性查询多个物理模型。此参数为必填。"],
    filter_rules: Annotated[Optional[str], "【可选】规则表达式过滤条件，JSON格式字符串。例如：'{\"rules\": [{\"model_id\": \"pressure_01\", \"field\": \"value\", \"operator\": \">\", \"value\": 1.6}]}'。支持多条规则通过 AND/OR 组合。"] = None
) -> dict:
    """查询小区设备历史数据（AI专用统计特征）
    
    查询指定时间范围内小区关联设备的历史数据，按物理模型编号精确查询。
    支持一次性查询多个物理模型编号，高效处理大规模时间序列数据，返回全面的统计特征用于AI分析。
    
    【返回的统计特征包含】AI模型可直接使用：
    
    基础统计：
    • 最大值、最小值、平均值、中位数、众数
    • 偏度、峰度
    
    离散程度：
    • 标准差、方差、变异系数
    • 极差、四分位数、四分位数间距
    
    趋势特征：
    • 总趋势斜率（线性回归）
    • 波动性（相邻值变化率的波动）
    • 变化率（总体变化趋势）
    • 单调性指数
    • 单调递增/递减段长度
    
    异常检测：
    • 异常值个数及具体值（IQR法则）
    • 最大跳跃值（相邻两点最大差值）
    • 跳跃点个数（超过3倍平均变化率的点）
    • 平台点个数（相同或极其接近的连续值）
    
    周期特征：
    • 峰值、谷值及其个数
    • 峰谷比（高低点对比）
    
    数据质量：
    • 有效数据点数、缺失值数及缺失率
    • 重复值个数及重复率
    
    返回结果为小区设备历史信息列表，每个小区包含：
    - villageName: 小区名字
    - villageId: 小区ID
    - devices[]: 设备列表，每个设备包含：
        - statisticalFeatures: 统计特征数据（AI专用，同步接收原始数据）
    
    使用场景：
    • ✓ AI模型特征工程和数据输入
    • ✓ 设备异常检测和故障诊断
    • ✓ 长期运行趋势分析
    • ✓ 故障模式识别
    • ✓ 设备性能对比
    • ✓ 专业的设备运维报告生成
    
    时间格式严格要求：
    • 格式必须是：yyyy-MM-dd HH:mm:ss
    • 不能写成其他格式如：2024-1-1、2024/01/01、2024-01-01 等
    • 时分秒不能省略，即使都是 00:00:00 也必须完整写出
    • 结束时间必须晚于开始时间
    
    【规则引擎 filter_rules 使用说明】
    
    filter_rules 是一个 JSON 字符串，支持复杂的数据过滤条件。
    
    支持的操作符：
    • > : 大于 (例：value > 1.6)
    • < : 小于 (例：value < 10)
    • >= : 大于等于 (例：value >= 20)
    • <= : 小于等于 (例：value <= 25)
    • == : 等于 (例：value == true)
    • != : 不等于 (例：value != 0)
    • in : 包含在列表中 (例：value in [1, 2, 3])
    • contains : 字符串包含 (例：value contains "error")
    
    【使用示例】
    
    1. 简单条件：查询压力值大于1.6的时间段
    filter_rules = '{"rules": [{"model_id": "pressure_01", "field": "value", "operator": ">", "value": 1.6}]}'
    
    2. 多条件 AND：查询温度在20-25℃ 且 压力值大于1.5m的时间段
    filter_rules = '{
        "rules": [
            {"model_id": "temp_01", "field": "value", "operator": ">=", "value": 20},
            {"model_id": "temp_01", "field": "value", "operator": "<=", "value": 25, "operator_to_next": "AND"},
            {"model_id": "pressure_01", "field": "value", "operator": ">", "value": 1.5, "operator_to_next": "AND"}
        ]
    }'
    
    3. 布尔值匹配：查询温度报警为 true 的时间段
    filter_rules = '{"rules": [{"model_id": "temp_alarm", "field": "value", "operator": "==", "value": true}]}'
    """
    # 工具会自动从上下文中获取 token
    # 处理多个物理模型编号：requests 库会自动将列表转换为多个同名参数（如 modelId=xxx&modelId=yyy）
    params = {
        "villageNumber": village_number,
        "startTime": start_time,
        "endTime": end_time,
        "modelId": model_id
    }
    
    # 如果提供了过滤规则，添加到参数中
    if filter_rules:
        params["filterRules"] = filter_rules
    
    # 调用API获取数据（包含统计特征和原始数据）
    response = _call_api(
        endpoint="/ai/query/village/device/history",
        method="GET",
        params=params
    )
    
    # 检查响应是否成功
    if response is None or "data" not in response:
        return response
    
    # 初始化规则引擎（如果提供了过滤规则）
    rule_engine = None
    raw_data_for_rules = {}  # 用于存储原始数据供规则引擎使用
    
    if filter_rules:
        try:
            rules_config = json.loads(filter_rules)
            rule_engine = RuleEngine(rules_config)
            logger.info(f"[data_query] 📋 规则引擎已初始化，规则数: {len(rule_engine.rules)}")
        except json.JSONDecodeError as e:
            logger.error(f"[data_query] ❌ 规则 JSON 解析失败: {str(e)}")
            return {
                "code": 400,
                "msg": f"过滤规则 JSON 格式错误: {str(e)}",
                "data": []
            }
    
    # 提取并处理数据，同步接收原始时间序列数据，但只返回统计特征给AI
    processed_response = {
        "code": response.get("code"),
        "msg": response.get("msg"),
        "data": [],
        "filter_applied": filter_rules is not None
    }
    
    if isinstance(response.get("data"), list):
        for village in response["data"]:
            processed_village = {
                "villageName": village.get("villageName"),
                "villageId": village.get("villageId"),
                "devices": []
            }
            
            # 每个小区只有一个设备，直接处理
            if isinstance(village.get("devices"), list) and len(village.get("devices", [])) > 0:
                device = village["devices"][0]
                
                # 接收rawData（时间序列）和statisticalFeatures
                processed_device = {}
                
                # 保留统计特征供AI处理
                if "statisticalFeatures" in device:
                    processed_device["statisticalFeatures"] = device["statisticalFeatures"]
                
                processed_village["devices"].append(processed_device)
                
                # 构建modelId -> modelName的映射（从thingsModels）
                model_name_map = {}
                if isinstance(device.get("thingsModels"), list):
                    for things_model in device["thingsModels"]:
                        model_id = things_model.get("modelId")
                        model_name = things_model.get("modelName")
                        if model_id:
                            model_name_map[model_id] = model_name
                
                # 发送原始时间序列数据给前端
                if "rawData" in device:
                    raw_data = device["rawData"]
                    
                    # 处理单个modelId的情况（rawData是时间序列对象）
                    if isinstance(raw_data, dict) and "timestamps" in raw_data:
                        model_id = raw_data.get("model_id")
                        model_name = model_name_map.get(model_id, model_id)
                        timestamps = raw_data.get("timestamps", [])
                        values = raw_data.get("values", [])
                        
                        # 如果需要过滤，保存数据到规则引擎
                        if rule_engine:
                            rule_engine.set_data(model_id, timestamps, values)
                            raw_data_for_rules[model_id] = {
                                "timestamps": timestamps,
                                "values": values,
                                "unit": raw_data.get("unit", "")
                            }
                        
                        frontend_data = {
                            "village_name": village.get("villageName"),
                            "village_id": village.get("villageId"),
                            "model_id": model_id,
                            "model_name": model_name,
                            "timestamps": timestamps,
                            "values": values,
                            "unit": raw_data.get("unit", ""),
                            "data_points_count": raw_data.get("data_points", 0),
                            "timestamp": datetime.now().isoformat()
                        }
                        _send_to_frontend("time_series_data", frontend_data)
                    
                    # 处理多个modelId的情况（rawData是字典，键为modelId）
                    elif isinstance(raw_data, dict):
                        for model_id, time_series in raw_data.items():
                            if isinstance(time_series, dict) and "timestamps" in time_series:
                                model_name = model_name_map.get(model_id, model_id)
                                timestamps = time_series.get("timestamps", [])
                                values = time_series.get("values", [])
                                
                                # 如果需要过滤，保存数据到规则引擎
                                if rule_engine:
                                    rule_engine.set_data(model_id, timestamps, values)
                                    raw_data_for_rules[model_id] = {
                                        "timestamps": timestamps,
                                        "values": values,
                                        "unit": time_series.get("unit", "")
                                    }
                                
                                frontend_data = {
                                    "village_name": village.get("villageName"),
                                    "village_id": village.get("villageId"),
                                    "model_id": model_id,
                                    "model_name": model_name,
                                    "timestamps": timestamps,
                                    "values": values,
                                    "unit": time_series.get("unit", ""),
                                    "data_points_count": time_series.get("data_points", 0),
                                    "timestamp": datetime.now().isoformat()
                                }
                                _send_to_frontend("time_series_data", frontend_data)
            
            processed_response["data"].append(processed_village)
    
    # 应用规则引擎过滤
    if rule_engine:
        filter_result = rule_engine.filter_data()
        
        if filter_result.get("error"):
            logger.error(f"[data_query] ❌ 规则过滤失败: {filter_result.get('error')}")
            processed_response["filter_error"] = filter_result.get("error")
        else:
            filtered_data = filter_result.get("filtered_data", {})
            matching_indices = filter_result.get("matching_indices", [])
            
            logger.info(f"[data_query] ✅ 规则过滤完成，匹配数据点数: {len(matching_indices)}")
            
            # 将过滤结果添加到响应中
            processed_response["filter_result"] = {
                "matching_count": len(matching_indices),
                "filtered_data": filtered_data
            }
    
    return processed_response


@tool
def query_village_models(
    village_number: Annotated[str, "小区编号，精确查询。例如：'V001'、'V002' 等。不能为空。"]
) -> dict:
    """查询小区物理模型列表
    
    通过小区编号查询小区关联设备的所有物理模型。
    
    返回结果为物理模型列表，每个模型包含：
    - modelId: 模型编号/标识符
    - modelName: 模型名称
    
    使用场景：
    • 查看小区有哪些可用的物理模型
    • 了解设备支持的位点信息
    • 为历史数据查询选择合适的位点
    • 列举设备的所有监测点
    """
    # 工具会自动从上下文中获取 token
    params = {
        "villageNumber": village_number
    }
    
    return _call_api(
        endpoint="/ai/query/village/models",
        method="GET",
        params=params
    )


def _send_to_frontend(event_type: str, data: dict):
    """发送数据给前端（通过 SSE 事件）"""
    send_sse_event(event_type, data, tag="trend_chart")



# 工具列表 - 在这里添加新的工具
DataQueryTool = [
    query_villages,
    query_village_device_running,
    query_village_device_history,
    query_village_models,
    # generate_trend_chart,
    # 在这里添加更多工具，例如：
    # get_device_list,
    # create_device,
    # update_device_config,
]

